package com.fastloan.mgt.customer.service.impl;

import com.fastloan.mgt.application.base.model.Application;
import com.fastloan.mgt.application.base.service.ApplicationService;
import com.fastloan.mgt.customer.anno.EnumObj;
import com.fastloan.mgt.customer.anno.TagAnno;
import com.fastloan.mgt.customer.enums.CustomerEnums;
import com.fastloan.mgt.customer.dao.*;
import com.fastloan.mgt.customer.enums.EnumInterface;
import com.fastloan.mgt.customer.model.*;
import com.fastloan.mgt.customer.model.vo.*;
import com.fastloan.mgt.customer.service.CustomerAmountService;
import com.fastloan.mgt.product.basics.model.Product;
import com.fastloan.mgt.product.basics.service.ProductService;
import com.fastloan.safe.core.param.RoleTypeEnum;
import com.fastloan.safe.core.util.ManagerKit;
import com.fastloan.safe.mgt.auth.dao.CmuRoleMapper;
import com.fastloan.safe.mgt.auth.dao.CmuUserRoleMapper;
import com.fastloan.safe.mgt.auth.model.CmuRole;
import com.fastloan.safe.mgt.auth.model.CmuUserRole;
import com.fastloan.safe.mgt.user.dao.CmuUserMapper;
import com.fastloan.safe.mgt.user.model.CmuUser;
import com.fastloan.utils.DateTimeUtil;
import com.kawins.base.BaseMapper;
import com.kawins.base.baseabs.BaseServiceImpl;
import com.kawins.supers.file.IFileManager;
import com.kawins.supers.file.core.FileLoadBean;
import com.kawins.supers.table.manager.DataTable;
import com.fastloan.mgt.customer.service.ZyCustomerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.constraints.NotNull;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;

import static com.fastloan.mgt.product.enums.ProductType.ADVANCE;

/**
 * @author gelon createTime 2017/11/06
 */
@org.springframework.stereotype.Service
public class ZyCustomerServiceImpl extends BaseServiceImpl<ZyCustomer> implements
        ZyCustomerService {

    @org.springframework.beans.factory.annotation.Autowired
    private com.fastloan.mgt.customer.dao.ZyCustomerMapper zyCustomerMapper;

    @Autowired
    private ZyCustomerBusinessMapper customerBusinessMapper;

    @Autowired
    private ZyCustomerFinancingMapper customerFinancingMapper;

    @Autowired
    private ZyCustomerStoreMapper customerStoreMapper;

    @Autowired
    private ZyCustomerMyBankMapper customerMyBankMapper;

    @Autowired
    private ZyCustomerOtherBankMapper customerOtherBankMapper;

    @Autowired
    private ZyCustomerLoanDemandMapper customerLoanDemandMapper;

    @Autowired
    private ZyCustomerMarketionMapper customerMarketionMapper;

    @Autowired
    private IFileManager fileManager;

    @Autowired
    private CmuUserMapper userMapper;

    @Autowired
    private CmuUserRoleMapper userRoleMapper;

    @Autowired
    private CmuRoleMapper roleMapper;

    @Autowired
    private ProductService productService;

    @Autowired
    private CustomerAmountService customerAmountService;

    @Autowired
    private ApplicationService applicationService;


    @Override
    protected BaseMapper<ZyCustomer> buildDao() {
        return zyCustomerMapper;
    }

    /**
     * 获取客户信息
     */
    @Override
    @DataTable(name = "queryCustomerExt")
    public List<CustomerExt> queryCustomerExt(Map<String, Object> map) {
        return zyCustomerMapper.queryCustomerExt(map);
    }

    /**
     * 新建客户 录入店铺信息
     */
    @Override
    @Transactional
    public void addByStore(ZyCustomerStore zyCustomerStore, ZyCustomer zyCustomer,
                           MultipartFile file) {
        FileLoadBean upload = null;
        if (file != null && file.getSize() != 0) {
            upload = fileManager.upload(file);
        }
        zyCustomer.setCustomerManagerId(ManagerKit.getUserId())
                .setCname(zyCustomerStore.getOwerName())
                .setPhoneNum(zyCustomerStore.getOwnerPhoneNum())
                .setStatus(CustomerEnums.CustomerStatus.NOT_STOCK.getCode())
                .setCreater(ManagerKit.getUserId())
                .setCreateTime(new Date());
//        if(zyCustomer.getCardNum() != null && zyCustomer.getCardType().equals(1)){
//            zyCustomer.setBirthday(IDCardUtil.getBirthdayByIDcard(zyCustomer.getCardNum()));
//            zyCustomer.setGender(IDCardUtil.getSexByIDCard(zyCustomer.getCardNum()).getCode());
//        }
        zyCustomerMapper.insertSelective(zyCustomer);
        String cId = zyCustomer.getId();
        zyCustomerStore.setCustomerId(cId);
        if (upload != null) {
            zyCustomerStore.setShoreImgId(upload.getFileId().toString());
        }
        customerStoreMapper.insertSelective(zyCustomerStore);
        customerBusinessMapper.insertSelective(new ZyCustomerBusiness().setCustomerId(cId));
        customerMyBankMapper.insertSelective(new ZyCustomerMyBank().setCustomerId(cId));
        customerLoanDemandMapper.insertSelective(new ZyCustomerLoanDemand().setCustomerId(cId));
        customerMarketionMapper.insertSelective(new ZyCustomerMarketion()
                .setCustomerId(cId)
                .setCustomerStatus(CustomerEnums.CustomerStatus.NOT_STOCK.getCode())
                .setCustomerManagerId(ManagerKit.getUserId())
                .setMarketionStatus(1)
                .setModifyTime(new Date()));
    }

    /**
     * 新建客户 只添加手机信息
     */
    @Override
    @Transactional
    public ZyCustomer addByPhone(String phone) {
        ZyCustomer zyCustomer = new ZyCustomer();
        zyCustomerMapper.insertSelective(zyCustomer.setPhoneNum(phone)
                .setStatus(CustomerEnums.CustomerStatus.NOT_STOCK.getCode())
                .setCreateTime(new Date()));
        String cId = zyCustomer.getId();
        customerStoreMapper.insertSelective(new ZyCustomerStore().setCustomerId(cId));
        customerBusinessMapper.insertSelective(new ZyCustomerBusiness().setCustomerId(cId));
        customerMyBankMapper.insertSelective(new ZyCustomerMyBank().setCustomerId(cId));
        customerLoanDemandMapper.insertSelective(new ZyCustomerLoanDemand().setCustomerId(cId));
        return zyCustomer;
    }


    /**
     * 获取客户所有维护信息
     */
    @Override
    public Map<String, Object> getCustomerInfo(String customerId) {
        ZyCustomer customer = zyCustomerMapper.selectByPrimaryKey(customerId);
        if (customer == null) {
            return null;
        }
        Map<String, Object> map = new HashMap<>();
        map.put("customer", customer);
        map.put("customerBusiness",
                customerBusinessMapper.selectOne(new ZyCustomerBusiness().setCustomerId(customerId)));
        map.put("customerFinancing",
                customerFinancingMapper.select(new ZyCustomerFinancing().setCustomerId(customerId)));
        map.put("customerLoanDemand", customerLoanDemandMapper
                .selectOne(new ZyCustomerLoanDemand().setCustomerId(customerId)));
        map.put("customerMyBank",
                customerMyBankMapper.selectOne(new ZyCustomerMyBank().setCustomerId(customerId)));
        map.put("customerOtherBank",
                customerOtherBankMapper.select(new ZyCustomerOtherBank().setCustomerId(customerId)));
        map.put("customerStore",
                customerStoreMapper.selectOne(new ZyCustomerStore().setCustomerId(customerId)));
        map.put("customerMarketion", new ZyCustomerMarketion().setCustomerId(customerId));
        map.put("customerMarketionCount", customerMarketionMapper
                .selectCount(new ZyCustomerMarketion().setCustomerId(customerId)));
        return map;
    }

    /**
     * 获取客户的营销信息
     */
    @Override
    @DataTable(name = "queryCustomerMartion")
    public List<CustomerMarketionExt> queryCustomerMartion(Map<String, Object> map) {
        return customerMarketionMapper.queryCustomerMartion(map);
    }

    @Override
    @Transactional
    public void updates(ZyCustomer customer, ZyCustomerBusiness customerBusiness,
                        List<ZyCustomerFinancing> customerFinancings,
                        ZyCustomerLoanDemand customerLoanDemand, ZyCustomerMarketion customerMarketion,
                        ZyCustomerMyBank customerMyBank,
                        List<ZyCustomerOtherBank> customerOtherBanks, ZyCustomerStore customerStore,
                        MultipartFile file) {
        if (file != null && file.getSize() != 0) {
            FileLoadBean fileLoadBean = fileManager.upload(file);
            customerStore.setShoreImgId(fileLoadBean.getFileId().toString());
        }

        StringBuffer sb = new StringBuffer();

        updateCompare(zyCustomerMapper.selectByPrimaryKey(customer.getId()), customer, sb, "基本信息");
        zyCustomerMapper.updateByPrimaryKeySelective(customer);

        updateCompare(customerBusinessMapper.selectByPrimaryKey(customerBusiness.getId()),
                customerBusiness, sb, "经营信息");
        customerBusinessMapper.updateByPrimaryKeySelective(customerBusiness);

        checkDelte(customerFinancingMapper
                        .select(new ZyCustomerFinancing().setCustomerId(customer.getId())), customerFinancings,
                sb);
        if (customerFinancings != null) {
            customerFinancings
                    .forEach(financing -> saveUploadFinancing(financing, customer.getId(), sb));
        }

        updateCompare(customerLoanDemandMapper.selectByPrimaryKey(customerLoanDemand.getId()),
                customerLoanDemand, sb, "贷款需求");
        customerLoanDemandMapper.updateByPrimaryKeySelective(customerLoanDemand);

        updateCompare(customerMyBankMapper.selectByPrimaryKey(customerMyBank.getId()),
                customerMyBank, sb, "与我行业务往来");
        customerMyBankMapper.updateByPrimaryKey(customerMyBank);

        checkDelete(customerOtherBankMapper
                        .select(new ZyCustomerOtherBank().setCustomerId(customer.getId())), customerOtherBanks,
                sb);
        if (customerOtherBanks != null) {
            customerOtherBanks
                    .forEach(otherBank -> saveUpdateOtherBank(otherBank, customer.getId(), sb));
        }

        updateCompare(customerStoreMapper.selectByPrimaryKey(customerStore.getId()), customerStore,
                sb, "店铺信息");
        customerStoreMapper.updateByPrimaryKeySelective(customerStore);

        if (customerMarketion == null) {
            customerMarketion = new ZyCustomerMarketion();
        }
        customerMarketionMapper.insertSelective(customerMarketion
                .setCustomerStatus(customer.getStatus())
                .setCustomerManagerId(ManagerKit.getUserId())
                .setModifyTime(new Date())
                .setChangeNote(sb.toString()));


    }

    private void checkDelete(List<ZyCustomerOtherBank> dbOthers,
                             List<ZyCustomerOtherBank> uploadOthers, StringBuffer sb) {
        dbOthers.forEach(dbOther -> inSetDelete(dbOther, uploadOthers, sb));
    }

    private void inSetDelete(ZyCustomerOtherBank dbOther, List<ZyCustomerOtherBank> uploadOthers,
                             StringBuffer sb) {
        ZyCustomerOtherBank find = uploadOthers.stream()
                .filter(uploadOther -> dbOther.getId().equals(uploadOther.getId())).findAny()
                .orElse(null);
        if (find == null) {
            customerOtherBankMapper.delete(dbOther);
            sb.append("与他行业务>删除: ").append(dbOther.getBankName()).append("--")
                    .append(dbOther.getLoanProject()).append("<br/>");
        }
    }

    private void checkDelte(List<ZyCustomerFinancing> dbFinancings,
                            List<ZyCustomerFinancing> uploadFinancings, StringBuffer sb) {
        dbFinancings.forEach(dbFinancing -> inSetDelete(dbFinancing, uploadFinancings, sb));

    }

    private void inSetDelete(ZyCustomerFinancing dbFinancing,
                             List<ZyCustomerFinancing> uploadFinancings, StringBuffer sb) {
        ZyCustomerFinancing find = uploadFinancings.stream()
                .filter(uploadFinancing -> dbFinancing.getId().equals(uploadFinancing.getId()))
                .findAny().orElse(null);
        if (find == null) {
            customerFinancingMapper.delete(dbFinancing);
            sb.append("融资经历>删除: ").append(dbFinancing.getFinancingExperience()).append("<br/>");
        }
    }

    /**
     * 查询存量客户
     */
    @Override
    @DataTable(name = "queryStockCustomers")
    public List<StockCustomer> queryStockCustomers(Map<String, Object> map) {
        return zyCustomerMapper.queryStockCustomers(map);
    }

    /**
     * 查询客户进件信息
     */
    @Override
    @DataTable(name = "queryApp")
    public List<CustomerAppExt> queryApp(Map<String, Object> map) {
        return zyCustomerMapper.queryApp(map);
    }

    /**
     * 绑定客户经理
     */
    @Override
    @Transactional
    public CmuUser bindManager(String managerCode) {
        CmuUser cmuUser = new CmuUser();
        cmuUser.setCode(managerCode);
        cmuUser = userMapper.selectOne(cmuUser);
        if (cmuUser == null) {
            return null;
        }
        CmuUserRole userRole = new CmuUserRole();
        userRole.setUserId(cmuUser.getId());
        userRole = userRoleMapper.selectOne(userRole);
        CmuRole role = roleMapper.selectByPrimaryKey(userRole.getRoleId());
        if (role.getIndexType().equals(RoleTypeEnum.MANAGER.getCode())) {
            ZyCustomer customer = zyCustomerMapper.selectByPrimaryKey(ManagerKit.getCustomerId());
            customer.setCustomerManagerId(cmuUser.getId());
            zyCustomerMapper.updateByPrimaryKeySelective(customer);
            return cmuUser;
        }
        return null;
    }

    @Override
    public ZyCustomer queryJxUserID(String userId) {
        return zyCustomerMapper.queryJxUserID(userId);
    }

    @Override
    public BigDecimal queryCreditLimits(String customerId, String productId) {
        return zyCustomerMapper.queryCreditLimits(customerId, productId, ManagerKit.getOrgId());
    }

    @Override
    public String queryCreditApplicationIdByCustomer(String applicationId) {
        Application application = applicationService.selectByPrimaryKey(applicationId);
        Product product = new Product();
        product.setOrgId(application.getOrgId());
        product.setProductType(ADVANCE.getType());
        product = productService.selectOne(product);
        if (product == null) {
            log.info("未查询到对应产品");
            return null;
        }
        CustomerAmount customerAmount = new CustomerAmount();
        customerAmount.setCustomerId(application.getCustomerId());
        customerAmount.setProductId(product.getProductId());
        customerAmount.setStatus(1);
        customerAmount = customerAmountService.selectOne(customerAmount);
        if (customerAmount != null) {
            return customerAmount.getApplicationId();
        }
        return null;
    }

    private void saveUpdateOtherBank(ZyCustomerOtherBank otherBank, String customerId,
                                     StringBuffer sb) {
        if (otherBank.getId() != null) {
            updateCompare(customerOtherBankMapper.selectByPrimaryKey(otherBank.getId()), otherBank,
                    sb, "与他行业务往来");
            customerOtherBankMapper.updateByPrimaryKeySelective(otherBank);
        } else {
            sb.append("与他行业务往来>新记录: ").append(otherBank.getBankName()).append(",")
                    .append(otherBank.getLoanProject()).append("<br/>");
            customerOtherBankMapper.insertSelective(otherBank.setCustomerId(customerId));
        }
    }

    private void saveUploadFinancing(ZyCustomerFinancing financing, String customerId,
                                     StringBuffer sb) {
        if (financing.getId() != null) {
            updateCompare(customerFinancingMapper.selectByPrimaryKey(financing.getId()), financing,
                    sb, "融资经历");
            customerFinancingMapper.updateByPrimaryKeySelective(financing);
        } else {
            customerFinancingMapper.insertSelective(financing
                    .setCustomerId(customerId)
                    .setCreateTime(new Date())
                    .setCreater(ManagerKit.getUserId()));
            sb.append("其他融资经历>新记录: ").append(financing.getFinancingExperience()).append("<br/>");
        }
    }


    public <T> void updateCompare(T dbBean, T compareBean, @NotNull StringBuffer sb, String moduleName) {
        Map<String, EnumInterface[]> enumsMap = new HashMap<>();
        Arrays.stream(dbBean.getClass().getDeclaredFields()).forEach(field -> pushEnums(dbBean, enumsMap, field));
        Arrays.stream(dbBean.getClass().getDeclaredFields()).forEach(field -> {
            try {
                checkChange(dbBean, compareBean, field, sb, moduleName, enumsMap);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        });
    }

    private <T> void pushEnums(T dbBean, Map<String, EnumInterface[]> enumsMap, Field field) {
        field.setAccessible(true);
        if (field.isAnnotationPresent(EnumObj.class)) {
            try {
                EnumInterface[] objects = (EnumInterface[]) field.get(dbBean);
                enumsMap.put(field.getAnnotation(EnumObj.class).mapping(), objects);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    private <T> void checkChange(T dbBean, T compareBean, Field dbField, @NotNull StringBuffer sb,
                                 String moduleName, Map<String, EnumInterface[]> enumsMap)
            throws IllegalAccessException {
        if (dbField.isEnumConstant()) {
            return;
        }
        Field compareField = Arrays.stream(compareBean.getClass().getDeclaredFields())
                .filter(field -> field.getName().equals(dbField.getName())).findFirst().orElse(null);

        dbField.setAccessible(true);
        compareField.setAccessible(true);

        String dbFieldStr = objStr(dbField, dbBean, enumsMap);
        String compareFieldStr = objStr(compareField, compareBean, enumsMap);

        if (!dbFieldStr.equals(compareFieldStr)) {
            if (dbField.isAnnotationPresent(TagAnno.class)) {
                String tag = tagField(dbField);
                sb.append(moduleName + ">" + tag + " 由: " + dbFieldStr + " 修改为: " + compareFieldStr
                        + "<br/>");
            }
        }
    }

    private String objStr(Field field, Object obj, Map<String, EnumInterface[]> enumMap)
            throws IllegalAccessException {
        Object fieldValue = field.get(obj);
        if (fieldValue == null) {
            return "";
        } else {
            String dbFieldStr;
            if (fieldValue instanceof Date) {
                Date date = (Date) fieldValue;
                dbFieldStr = DateTimeUtil.format(date, DateTimeUtil.NORM_DATETIME_PATTERN);
            } else {
                dbFieldStr = fieldValue.toString();
            }
            if (enumMap.containsKey(field.getName())) {
                EnumInterface[] enumInterfaces = enumMap.get(field.getName());
                String value = Arrays.stream(enumInterfaces).filter
                        (enumInterface -> enumInterface.getCode().toString().equals(dbFieldStr))
                        .findFirst().get().getName();
                return value;
            }
            return dbFieldStr;
        }
    }

    private String tagField(Field dbField) {
        String name = dbField.getAnnotation(TagAnno.class).name();
        if (name.contains(" ")) {
            name = name.substring(0, name.indexOf(' '));
        }
        return name;
    }


}
